/**
E.g., consider a Rectangle class that has a left&right point fields.

An erroneous programmer might make the following mistakes:
class Rectangle<I> {
  private Point<I> left;
  private Point<I> right;

  // Rectangle want to enforce the invariant the left.x <= right.x
  public Rectangle<I>(Point<I> p1, Point<I> p2) {
      if (p1.x > p2.x) { ... swap p1,p2 }
      this.left = p1; // BAD: didn't copy the argument, so the invariant might be voilated from the outside
      this.right = p2; // BAD: dido
  }

  public Point<I> getLeft() { 
      return left; // BAD: If we have a mutable rectangle, the invariant can be broken from the outside
  }
  public Rectangle<I> clone() {
      return (Rectangle<I>) this.clone(); // BAD: shallow copy! left&right will be shared between two instances of rectangle
  }
}


 */





class Rectangle<O,I> { 
    Point<This,I> left;

    Point<O,I> notThisPoint; // just for the foo example below
    Point<I,World> publicPoint;

    Rectangle(Point<RO,World> l) {
        this.directSet( l.clone() );
    }
    @RO boolean equalsTo(Rectangle<RO,World> r) { ... }
    @M void directSet(Point<This,I> l) {
        this.left = l;
    }
    @M void set(Point<RO,World> l) {
        this.left = l.clone();
    }
    @RO Point<This,I> get() {
        return this.left;
    }
    @M Point<M,This> get2() { 
        return this.left; // also ok, but anyone calling get2 from the outside will get a RO Point due to method invocation rule.
    }
    @RO <NI,NO> Point<NI,NO> clone() {
        return new Point<NI,NO>(x,y);
    }

    // Illegal due to ownership nesting rule.
    @M Vector<M,World,Point<M,This>> exposePoint() { 
        // return a vector containing this.left
    }
    
    

    // examples to show how the type rules work
    @M void foo() {
        this.directSet( new Point<This,Mutable>(...) ); // ok
        Rectangle<This,Mutable> otherRec = ... (either new or this)
        otherRec.left = ... ; // illegal (field access rule)
        this.left = ... ; // legal
        otherRec.directSet( ... ); // illegal (method invocation rule)
        this.directSet( ... ); // legal

        
        Rectangle<RO,World> r1;
        Rectangle<IM,World> r2;
        Rectangle<M,World> r3;
        Point<RO,This> p = r1.left; 
        Point<IM,This> p = r2.left; 
        Point<M,This> p = r3.left; // illegal (field access rule)
        Point<RO,This> p = r1.get(); 
        Point<IM,This> p = r2.get(); 
        Point<M,This> p = r3.get(); // illegal (method invocation rule)

        Rectangle<M,This> r4;
        r4.left = ...; // illegal cause O(left)=This
        r4.notThisPoint = ...; // ok
        r4.publicPoint = ...; // ok
    }
};






